package com.example.test;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.VpnService;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.util.Log;

import androidx.core.app.NotificationCompat;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import engine.Engine;

public class MyVpnService extends VpnService {
    private static final String ADDRESS = "10.0.0.2";
    private static final String ROUTE = "0.0.0.0";
    private static final String DNS = "8.8.8.8";
      //private static final String PROXY_SOCKS = "uhrmacherorrell:RQ2E8qInxj@161.77.229.107:50101"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "customer-202407090501582631-region-440100-session-5n6wqzgnt1z2uwu:O7PoFX0H@proxy.quanminip.com:31100"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "customer-202407090501582631-region-440100-session-5n6wqzgnt1z2uwu:O7PoFX0H@proxy.quanminip.com:31100"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "18709287807:zx8825@117.84.67.54:40042"; // Your SOCKS5 server
    private static final String PROXY_SOCKS = "ymf0dj:2a7ob86l@61.160.23.44:59000"; // Your SOCKS5 server
   // private static final String PROXY_SOCKS = "tvix12:AYJ1Qbez@43.248.99.36:62001"; // Your SOCKS5 server
   // private static final String PROXY_SOCKS = "59.42.30.90:4331"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "customer-202407090501582631-region-440000-session-v6fn8kuy8drpdkx:O7PoFX0H@116.26.7.28:40026"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "gjjyafut:t91jndzi@47.108.189.170:21082"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "terencejumping:QVWz8zwtxc@161.77.55.101:50101"; // Your SOCKS5 server
      //private static final String PROXY_SOCKS = "customer-d12980:1613e097@172.65.64.115:13192"; // Your SOCKS5 server
    //private static final String HTTP = "172.65.64.115:13192@proxy.ipipgo.com:31212"; // Your SOCKS5 server
   // private static final String PROXY_SOCKS = "172.18.6.22:64974"; // Your SOCKS5 server
    //private static final String PROXY_SOCKS = "terencejumping:QVWz8zwtxc@161.77.55.101:50101"; // Your SOCKS5 server
    // private static final String SHADOWSOCKS = "https://s1.trojanflare.one/clashx/01593513-f46d-44a2-bacd-dd8066dcb104"; // Your SOCKS5 server
    //private static final String SOCKS5 = "socks5://l6W1sjwclS:80766829@154.200.18.18:6001"; // Your SOCKS5 server

    // You could spin up a local SOCK5 server on your workstation with:
    // ssh -ND "*:8080" -q -C -N <username>@<remote-host>

    private final ExecutorService executors = Executors.newFixedThreadPool(1);
    private ParcelFileDescriptor tun;
    private static final String TAG = "vpnService";
    private static final String CHANNEL_ID = "vpn_channel";
    private static final int NOTIFICATION_ID = 1;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"===服务创建===onCreate");
        // 创建并设置通知渠道（适用于 Android 8.0 及更高版本）
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "VPN Service", NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
        startVpn();
    }

    private void startVpn() {
        if (tun == null) {
            try {
                Builder builder = new Builder()
                        .addAddress(ADDRESS, 24)
                        // .addRoute(ROUTE, 0)
                        .addDnsServer(DNS)
                        .addDisallowedApplication(this.getPackageName());

                // let DNS queries bypass VPN if SOCKS server does not support UDP bind
                addRoutesExcept(builder, DNS, 32);
                tun = builder.establish();
            } catch (PackageManager.NameNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        String proxySocks;
        if (TextUtils.isEmpty(Constants.IP) || TextUtils.isEmpty(Constants.PORT)) {
            proxySocks = PROXY_SOCKS;
        } else {
            proxySocks = String.format("%s%s%s%s", Constants.DEFAULT_PROXY, Constants.IP, Constants.UNIT, Constants.PORT);
        }
        Log.d("ProxySocks", "===获取到的代理信息为===" + proxySocks);
        engine.Key key = new engine.Key();
        key.setMark(0);
        key.setMTU(0);
        key.setDevice("fd://" + tun.getFd());
        key.setInterface("");
        key.setLogLevel("debug");
        key.setProxy(proxySocks);
        key.setRestAPI("");
        key.setTCPSendBufferSize("");
        key.setTCPReceiveBufferSize("");
        key.setTCPModerateReceiveBuffer(false);

        engine.Engine.insert(key);
        executors.submit(Engine::start);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 将 VPN 服务设置为前台服务
        startForeground(NOTIFICATION_ID, buildNotification());
        startVpn();
        return START_STICKY;
    }

    private Notification buildNotification() {
        // 创建前台服务通知
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("VPN Service")
                .setContentText("VPN is running")
                .setSmallIcon(R.drawable.ic_launcher_background)
                .setPriority(NotificationCompat.PRIORITY_LOW);
        return builder.build();
    }

    public  void disconnectVpn(){
        if (executors != null) {
            executors.shutdownNow();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"===服务停止===onDestroy");
        if (executors != null) {
            executors.shutdownNow();
        }
    }

    /**
     * Computes the inverted subnet, routing all traffic except to the specified subnet. Use prefixLength
     * of 32 or 128 for a single address.
     *
     * @see <a href="https://stackoverflow.com/a/41289228"></a>
     */
    private void addRoutesExcept(Builder builder, String address, int prefixLength) {
        try {
            byte[] bytes = InetAddress.getByName(address).getAddress();
            for (int i = 0; i < prefixLength; i++) { // each entry
                byte[] res = new byte[bytes.length];
                for (int j = 0; j <= i; j++) { // each prefix bit
                    res[j / 8] = (byte) (res[j / 8] | (bytes[j / 8] & (1 << (7 - (j % 8)))));
                }
                res[i / 8] ^= (1 << (7 - (i % 8)));

                builder.addRoute(InetAddress.getByAddress(res), i + 1);
            }
        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        }
    }
}
